/*
 * Copyright (c) 2011, Marc-Andre Ferland - madrang@gmail.com
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the The Warrent Team nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *     * This software is free for non-commercial use. You may not use this
 *       software, in whole or in part, in support of any commercial product
 *       without the express consent of the author.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE WARRENT TEAM BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;

namespace OsHelper.UsbNet.Descriptors
{
	public class LanguageIdentifiersDescriptor
	{
		private Descriptor BaseDesc;
		
		public LanguageIdentifiersDescriptor ()
		{
			this.BaseDesc = new Descriptor();
			this.BaseDesc.Length = (byte)Descriptor.Size;
			this.BaseDesc.Type = new DescriptorType(StandardDescriptorSubType.String);
			this.LanguageIdentifiers = new List<LanguageIdentifiers>();
		}
		
		public LanguageIdentifiersDescriptor (List<LanguageIdentifiers> LangList)
		{
			this.BaseDesc = new Descriptor();
			this.BaseDesc.Length = (byte)Descriptor.Size;
			this.BaseDesc.Type = new DescriptorType(StandardDescriptorSubType.String);
			this.LanguageIdentifiers = LangList;
		}
		
		public byte[] ToBytes()
		{
			byte MaxLength = (byte)Math.Min(255, (this.LanguageIdentifiers.Count * sizeof (ushort)) + Descriptor.Size);
			this.BaseDesc.Length = MaxLength;
			
			byte[] DescData = Serialyser.RawSerialize(this.BaseDesc);
			
			byte[] ResultData = new byte[MaxLength];
			
			Array.Copy(DescData, 0, ResultData, 0, Descriptor.Size);
			
			for (int ItemCount = 0; ItemCount < this.LanguageIdentifiers.Count; ItemCount++) {
				int Offset = (ItemCount * sizeof (ushort)) + Descriptor.Size;
				
				if(MaxLength < Offset + sizeof (ushort))
					break;
				
				byte[] TmpData = BitConverter.GetBytes((ushort)this.LanguageIdentifiers[ItemCount]);
				Array.Copy(TmpData, 0, ResultData, Offset, TmpData.Length);
			}
			
			return ResultData;
		}
		
		public static LanguageIdentifiersDescriptor FromBytes(byte[] Data)
		{
			if(Data == null)
				throw new ArgumentNullException("Data");
			
			if(Data.Length < Descriptor.Size)
				throw new ArgumentException();
			
			byte[] DescData = new byte[Descriptor.Size];
			Array.Copy(Data, 0, DescData, 0, Descriptor.Size);
			
			LanguageIdentifiersDescriptor LangDesc = new LanguageIdentifiersDescriptor();
			LangDesc.BaseDesc = Descriptor.FromBytes(Data);
			
			int Elem = (LangDesc.BaseDesc.Length - Descriptor.Size) / sizeof (ushort);
			
			if(Elem <= 0)
				return LangDesc;
			
			for (int i = 0; i < Elem; i++) {
				LanguageIdentifiers Lang;
				Lang = (LanguageIdentifiers)BitConverter.ToInt16(Data, (i * sizeof (ushort)) + Descriptor.Size);
				LangDesc.LanguageIdentifiers.Add(Lang);
			}
			
			return LangDesc;
		}
		
		public List<LanguageIdentifiers> LanguageIdentifiers { get; set; }
	}
	
	public class StringDescriptor
	{
		private Descriptor BaseDesc;
		
		public StringDescriptor ()
		{
			this.BaseDesc = new Descriptor();
			this.Type = new DescriptorType(StandardDescriptorSubType.String);
		}
		
		public StringDescriptor (string s)
		{
			this.Type = new DescriptorType(StandardDescriptorSubType.String);
			this.Value = s;
		}
		
		public byte[] ToBytes()
		{
			byte[] StringData = Encoding.Unicode.GetBytes(this.Value);
			
			this.BaseDesc.Length = (byte)Math.Min(255, StringData.Length + Descriptor.Size);
			
			byte[] DescData = Serialyser.RawSerialize(this.BaseDesc);
			byte[] ResultData = new byte[this.BaseDesc.Length];
			
			Array.Copy(DescData, 0, ResultData, 0, Descriptor.Size);
			Array.Copy(StringData, 0, ResultData, Descriptor.Size, this.BaseDesc.Length - Descriptor.Size);
			
			return ResultData;
		}
		
		public static StringDescriptor FromBytes(byte[] Data)
		{
			if(Data == null)
				throw new ArgumentNullException("Data");
			
			if(Data.Length < Descriptor.Size)
				throw new ArgumentException();
			
			byte[] DescData = new byte[Descriptor.Size];
			Array.Copy(Data, 0, DescData, 0, Descriptor.Size);
			
			StringDescriptor StrDesc = new StringDescriptor();
			
			StrDesc.BaseDesc = Descriptor.FromBytes(Data);
			
			if((StrDesc.BaseDesc.Length - Descriptor.Size) <= 0)
				StrDesc.Value = string.Empty;
			
			byte[] ByteData = new byte[StrDesc.BaseDesc.Length - Descriptor.Size];
			Array.Copy(Data, Descriptor.Size, ByteData, 0, ByteData.Length);
			StrDesc.Value = Encoding.Unicode.GetString(ByteData, 0, ByteData.Length);
			
			return StrDesc;
		}
		
		public byte Length {
			get { return this.BaseDesc.Length; }
			private set { this.BaseDesc.Length = value; }
		}
		
		public UsbNet.Descriptors.DescriptorType Type {
			get { return this.BaseDesc.Type; }
			private set { this.BaseDesc.Type = value; }
		}
		
		public string Value { get; set; }
		
	}
}
